/**
 *  MOPS 插座连接SmartHomeNode控制程序
 *  硬件：MOPS 智能插座
 *  配网：固定配网方式
 *  命令：
 *    1、ON    // 开
 *    2、OFF   // 关
 *    3、NAME:ON  // 开
 *    4、NAME:OFF // 关
 *  时间：2021-03-11
 */
#include <ESP8266WiFi.h>      // WIFI 头文件
WiFiClient client;

/********************** 系统配置 ***********************/

/* wifi 名称 */
const char *SSID = "home_2.4";
/* wifi 密码 */
const char *PASSWORD = "yuyu0123456";
/* Server 的 IP 地址 */
const char *HOST = "smart.home";
/* 节点名称 */
const String NAME = "MOPS06";
/* Server 的端口号 */
const int PORT = 50001;

/********************** 硬件配置 ***********************/
const int LED = 12;           // LED引脚
const int SwitchPin = 15;     // 继电器引脚
const int ButtonPin = 13;     // 按钮引脚
/******************************************************/

/* 接收到的每一位数据 */
char readByte = ' ';
/* 缓存所有接收到的字节 */
String readData = "";
/* 控制码 */
String CONTROL = "STATUS/:" + NAME;
const String OPEN = "/:ON";
const String CLOSE = "/:OFF";

/* 运行时间检测 */
const int debouncdDelay = 30000;      // 延时间隔（会随机 + 0~9秒）
unsigned long lastDebounceTime = 0;   // 延时记录（不会为负数）

/**
 * 周期上报心跳
 */
void heart() {
    CONTROL = "STATUS/:" + NAME;
    if (digitalRead(LED) == HIGH) {
        CONTROL += CLOSE;
    } else {
        CONTROL += OPEN;
    }
    client.write(&CONTROL[0]);
}

/**
 * 系统 灯亮一下
 */
void alarmLED() {
    digitalWrite(LED, LOW);
    delay(333);
    digitalWrite(LED, HIGH);
}

/**
 * 继电器开
 */
void switchON() {
    digitalWrite(LED, LOW);
    digitalWrite(SwitchPin, HIGH);
    heart();
}

/**
 * 继电器关
 */
void switchOFF() {
    digitalWrite(LED, HIGH);
    digitalWrite(SwitchPin, LOW);
    heart();
}

/**
 * 控制开关
 */
void controlSwitch(String constrol) {
    if (constrol == "ON") {
      switchON();
    }
    if (constrol == "OFF") {
      switchOFF();
    }
    if (constrol == NAME + ":ON") {
      switchON();
    }
    if (constrol == NAME + ":OFF") {
      switchOFF();
    }
}

/**
 * 检查按键按下
 */
void pushButton() {
  int pushCheck = analogRead(ButtonPin);
  if (pushCheck == LOW) {
    delay(3); // 防抖处理
    pushCheck = analogRead(ButtonPin);
    if (pushCheck == LOW) {
      int ledStatus = analogRead(LED);
      if (ledStatus == LOW) {
          switchOFF();
      } else {
          switchON();
      }
      delay(600);
    }
  }
}

/**
 * TCP 服务端发送过来的数据拼装字符成字符串
 */
void tcpData() {
    while (client.available())
    {
        readByte = client.read();
        readData += readByte;
        delay(1);
    }
}

/**
 *  非连接的异常处理
 */
void linkException() {
  while (!client.connected())
  {
    if (!client.connect(HOST, PORT))
    {
      Serial.println("connected excetpicon!");
      digitalWrite(SwitchPin, LOW); // 断网关闭继电器
    } else {
      heart();     // 重新连接后登录服务器
    }
    alarmLED();    // LED 闪烁提示
    delay(666);    // 延时再次检测
  }
}

/**
 * 初始化TCP 链接
 */
void linkInit() {
    Serial.println(SSID);
    WiFi.begin(SSID, PASSWORD);
    /* WiFi.status() 返回wifi链接状态  */
    while (WiFi.status() != WL_CONNECTED)
    {
        delay(666);
        Serial.print(".");
    }
    Serial.println("");
    Serial.println("WiFi connected");
    Serial.println("IP address: ");
    Serial.println(WiFi.localIP());
}

/**
 * 系统初始化
 * [setup description]
 */
void setup() {
  Serial.begin(115200);         // 配置串口
  Serial.println("");
  Serial.println("***** System init *****" );
  pinMode(LED, OUTPUT);
  digitalWrite(LED, HIGH);      // 关闭LED
  pinMode(SwitchPin, OUTPUT);   
  digitalWrite(SwitchPin, LOW); // 关闭继电器
  pinMode(ButtonPin, INPUT);
  linkInit();                   // 初始化服务器连接
  ESP.wdtEnable(10000);         // 使能软件看门狗的触发间隔
}

/**
 * 主方法
 * [loop description]
 */
void loop() {
  linkException();      // 检查TCP连接
  ESP.wdtFeed();        // 喂狗
  pushButton();         // 检查按键按下
  tcpData();            // 查看缓存池中数据
  /* 检查接收消息 */
  if (readData != "") {
    controlSwitch(readData);
    readData = "";
  } else {
    delay(9);           // 休息一下
  }
  // 置0后立即更新
  if ((millis() - lastDebounceTime) > (debouncdDelay + random(9999)))
  {
    lastDebounceTime = millis();  // 重新赋值上一次时间
    heart();            // 上报心跳
  }
}
